package com.lovo.gateway.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lovo.common.bean.User;
import com.lovo.common.result.GlobalHandleException;
import com.lovo.common.result.Result;
import com.lovo.common.result.ResultCode;
import com.lovo.common.service.AuthUserService;
import com.lovo.common.util.JWTUtil;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 *  身份认证过滤器
 */
@Component
public class AuthenticationFilter implements GlobalFilter {
    @Autowired
    private ShiroFilterFactoryBean shiroFilterFactoryBean;
    @Autowired
    private AuthUserService authUserService;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String authoriation = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);

        String path = request.getPath().value();

        Map<String,String> filterMap = shiroFilterFactoryBean.getFilterChainDefinitionMap();
        for(Map.Entry<String,String> entry: filterMap.entrySet()){
            String key = entry.getKey();
            String value = entry.getValue();
            key = key.replaceAll("\\*\\*",".*");
            if(path.matches("^"+key+"$") && "anon".equals(value)){
                return chain.filter(exchange);
            }
        }

        if(authoriation == null){
            return writeValueAsString(exchange.getResponse(), Result.fail(ResultCode.USER_NOT_LOGGED_IN));
        }
        if(!authoriation.startsWith("Bearer ")){
            return writeValueAsString(exchange.getResponse(), Result.fail(ResultCode.USER_NOT_LOGGED_IN));
        }
        String token = authoriation.substring(7);
        String username;
        try {
            username = JWTUtil.getAudience(token);
        } catch (GlobalHandleException e) {
            return writeValueAsString(exchange.getResponse(), Result.fail(ResultCode.USER_NOT_LOGGED_IN));
        }
        User user = authUserService.getByUsername(username);
        if(user == null){
            return writeValueAsString(exchange.getResponse(), Result.fail(ResultCode.USER_NOT_EXIST));
        }
        // 验证 token
        try {
            JWTUtil.verifyToken(token,user.getPwd());
        } catch (GlobalHandleException e) {
            return writeValueAsString(exchange.getResponse(), Result.fail(ResultCode.USER_AUTHENTICATION_ERROR));
        }
        return chain.filter(exchange);
    }

    private Mono<Void> writeValueAsString(ServerHttpResponse response, Result result) {
        ObjectMapper mapper = new ObjectMapper();
        response.getHeaders().add("Content-Type","application/json;charset=utf-8");
        try {
            return response.writeWith(Mono.just(response.bufferFactory().wrap(mapper.writeValueAsString(result).getBytes(StandardCharsets.UTF_8))));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }


    }
}
